package com.quwan.app.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.quwan.app.service.MemberService;
import com.quwan.app.vo.*;
import com.quwan.app.vo.account.BindAccParams;
import com.quwan.app.vo.pay.TransInfoDTO;
import com.quwan.app.vo.pay.TransferParams;
import com.quwan.app.vo.pay.TransferResult;
import com.quwan.common.BaseService;
import com.quwan.common.Check;
import com.quwan.common.ImMsgType;
import com.quwan.common.enums.*;
import com.quwan.common.exception.ExpCode;
import com.quwan.common.exception.LoginException;
import com.quwan.common.exception.ResponseException;
import com.quwan.common.exception.ServiceException;
import com.quwan.common.query.LambdaQueryWrapperX;
import com.quwan.common.result.PageResult;
import com.quwan.component.AsyncTaskComponent;
import com.quwan.component.PaymentComponent;
import com.quwan.component.TencentComponent;
import com.quwan.config.yml.ImConfig;
import com.quwan.config.yml.OssConfig;
import com.quwan.config.yml.PaymentBalanceConfig;
import com.quwan.constans.AppConst;
import com.quwan.constans.CacheKey;
import com.quwan.entity.*;
import com.quwan.manager.controller.dto.BalanceChangeLog;
import com.quwan.manager.controller.dto.MemberDTO;
import com.quwan.manager.controller.dto.MemberDetailDTO;
import com.quwan.mapper.*;
import com.quwan.security.JwtTokenUtil;
import com.quwan.utils.DateUtils;
import com.quwan.utils.NumberUtils;
import com.quwan.utils.Parse;
import com.quwan.utils.PayUtil;
import com.quwan.utils.redis.Redis;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;


/**
 * @author quan
 * @date 2021-06-07 16:04
 */

@Slf4j
@Service
@RequiredArgsConstructor
public class MemberServiceImpl extends BaseService implements MemberService {
    @Autowired
    private PaymentComponent paymentComponent;
    private final TencentComponent tencentComponent;
    private final TVerifyCodeMapper verifyCodeMapper;
    private final TMemberFollowMapper memberFollowMapper;
    private final TMemberBalanceLogMapper memberBalanceLogMapper;
    private final TMemberMapper memberMapper;
    private final JwtTokenUtil jwtTokenUtil;
    private final TGuestMapper guestMapper;
    private final TMemberVisitMapper memberVisitMapper;
    private final TMemberAlbumMapper memberAlbumMapper;
    private final TMemberAskMapper memberAskMapper;
    private final TMemberReportMapper memberReportMapper;
    private final TMemberVipMapper vipMapper;
    private final TCollectOrderMapper collectOrderMapper;
    private final PasswordEncoder passwordEncoder;
    private final AsyncTaskComponent asyncTaskComponent;
    private final TMemberBlackListMapper blackListMapper;
    private final TProductCategoryMapper categoryMapper;
    private final TDynamicFollowMapper dynamicFollowMapper;
    private final TPublishOrderMapper publishOrderMapper;
    private final TMemberRecommendMapper memberRecommendMapper;
    private final TOrderCommentMapper orderCommentMapper;
    private final TDynamicCommentMapper dynamicCommentMapper;
    private final TMemberDynamicMapper dynamicMapper;
    private final TSpreadSettingMapper spreadSettingMapper;
    private final TSpreadProfitListMapper spreadProfitListMapper;
    private final C2cOrderMapper orderMapper;
    private final TDispatchOrderMapper dispatchOrderMapper;
    private final TSystemPushMsgMapper systemPushMsgMapper;
    private final OssConfig ossConfig;
    private final PaymentBalanceConfig balanceConfig;
    private final ImConfig imConfig;
    private final Redis redis;
    @Qualifier("jwtUserDetailsServiceImpl")
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private HttpServletRequest request;
    @Value("${sms.codeLength}")
    private Integer smsCodeLength;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Value("${spring.profiles.active}")
    private String env;
    @Value("${member.head}")
    private String memberHead;

    @Override
    public boolean generatePhoneVcode(String mobile) {
        String code = NumberUtils.generateCode(smsCodeLength);
        LocalDate current = LocalDate.now();
        TVerifyCode verifyCode = getVerifyCodeByMobile(mobile);
        if (verifyCode == null) {
            TVerifyCode record =
                    new TVerifyCode()
                            .setMobile(mobile)
                            .setCode(code)
                            .setExpireTime(LocalDateTime.now().plusSeconds(TimeUnit.MILLISECONDS.toSeconds(AppConst.CODE_EXPRES_TIME)))
                            .setCurrDate(current);
            if (verifyCodeMapper.insert(record) == 1) {
                return tencentComponent.sendSms(mobile, code);
                //return aliComponent.sendSms(mobile, code);
            }
        } else {
            LocalDate codeCountDay = verifyCode.getCurrDate();
            if (current.isEqual(codeCountDay)) {
                if (verifyCode.getCount() > AppConst.SMS_CODE_LIMIT)
                    throw new LoginException(ExpCode.LOGIN_VCODE_MAX.getCode(), ExpCode.LOGIN_VCODE_MAX.getMsg());
            }
            LocalDateTime expireTime = verifyCode.getExpireTime();
            if (LocalDateTime.now().isAfter(expireTime)) {
                verifyCode
                        .setMobile(null)
                        .setAddTime(null)
                        .setCode(code)
                        .setExpireTime(LocalDateTime.now().plusSeconds(TimeUnit.MILLISECONDS.toSeconds(AppConst.CODE_EXPRES_TIME)))
                        .setCurrDate(current)
                        .setCount(current.equals(codeCountDay) ? verifyCode.getCount() + 1 : 1);
                if (verifyCodeMapper.updateById(verifyCode) == 1) {
                    return tencentComponent.sendSms(mobile, code);
                }
            } else
                throw new ResponseException(ExpCode.PHONE_CODE_VALID.getCode(), ExpCode.PHONE_CODE_VALID.getMsg());

        }
        log.error("sms err phone::{}::code::{}", mobile, code);
        return false;
    }

    @Override
    public TMember getMemberInfoById(String id) {
        TMember member = memberMapper
                .selectOne(
                        new LambdaQueryWrapper<TMember>()
                                .select(TMember::getAutoId, TMember::getId, TMember::getNickName, TMember::getParentId, TMember::getGender, TMember::getMobile,
                                        TMember::getServiceLevel, TMember::getImgUrl, TMember::getBirthday, TMember::getArea, TMember::getSign, TMember::getIdentity,
                                        TMember::getJob, TMember::getHeight, TMember::getPassword, TMember::getBalance, TMember::getAge, TMember::getVersion, TMember::getDd,
                                        TMember::getWxOpenId, TMember::getZfbOpenId, TMember::getFaceStatus, TMember::getIdStatus, TMember::getStatus)
                                .eq(TMember::getId, id)
                );
        return member == null ? null : StringUtils.isBlank(member.getImgUrl()) ? member : member.setImgUrl(ossConfig.getHostname() + "/" + member.getImgUrl());
    }

    @Override
    public String vCodeLogin(String mobile, String code, Long parentId, String guestId) {
        authPhoneCode(mobile, code);
        boolean fist = false;
        TGuest guest = null;
        TMember memberInfo = getMemberInfoByMobile(mobile);
        if (memberInfo == null) {
            //首次登录
            if (StringUtils.isNotBlank(guestId)) guest = guestMapper.selectById(guestId);
            TMember record =
                    new TMember()
                            .setMobile(mobile)
                            .setNickName("user" + redis.incr(CacheKey.USER.userCode))
                            .setImgUrl(memberHead)
                            .setSource(request.getHeader(DeviceEnum.HEADER) == null ? DeviceEnum.ANDROID.getType() : Integer.parseInt(request.getHeader(DeviceEnum.HEADER)))
                            .setParentId(parentId)
                            .setId(guest == null ? IdWorker.getId() : guest.getId());

            if (memberMapper.insert(record) != 1) {
                log.error("会员注册失败 mobile::{}", mobile);
                throw new ServiceException("会员注册失败");
            }
            memberInfo = record;
            fist = true;
        }
        String account = String.format("%s@@" + AppConst.MEMBER_MODULE, mobile);
        final UserDetails userDetails = userDetailsService.loadUserByUsername(account);
        String token = jwtTokenUtil.generateToken(userDetails);
        if (guest != null && fist)
            guestMapper
                    .updateById(
                            new TGuest()
                                    .setId(Long.parseLong(guestId.trim()))
                                    .setConvertMember(1));
        asyncTaskComponent.addLoginRecord(memberInfo.getId(), fist ? LoginStatusEnum.REGISTRY.getType() : LoginStatusEnum.LOGIN.getType(), fist ? null : request.getHeader(DeviceEnum.HEADER));
        return token;
    }

    @Override
    public TVerifyCode getVerifyCodeByMobile(String mobile) {
        return verifyCodeMapper
                .selectOne(
                        new QueryWrapper<>(
                                new TVerifyCode()
                                        .setMobile(mobile))
                );
    }

    @Override
    public TMember getMemberInfoByMobile(String mobile) {
        return memberMapper
                .selectOne(
                        new QueryWrapper<>(
                                new TMember()
                                        .setMobile(mobile)));
    }

    @Override
    public MemberDashboardData getDashboardData(Long mId) {
        return memberFollowMapper.selectDashboardDataByMId(mId);
    }

    @Override
    public TMember getMemberMoneyInfo(Long mId) {
        return memberMapper
                .selectOne(
                        new LambdaQueryWrapper<TMember>()
                                .select(TMember::getAutoId, TMember::getId, TMember::getBalance, TMember::getConsumeMoney, TMember::getOperateMoney,
                                        TMember::getRechargeMoney, TMember::getIncomeMoney, TMember::getPopularMoney, TMember::getVersion, TMember::getParentId)
                                .eq(TMember::getId, mId)
                );
    }

    @Override
    public String getNickNameById(Long id) {
        TMember member =
                memberMapper
                        .selectOne(
                                new LambdaQueryWrapper<TMember>()
                                        .select(TMember::getNickName)
                                        .eq(TMember::getId, id)
                        );

        return member == null ? "" : member.getNickName();
    }

    @Override
    public List<TMemberFollow> getMemberFollowObj(String mId) {
        return memberFollowMapper
                .selectList(
                        new LambdaQueryWrapper<TMemberFollow>()
                                .select(TMemberFollow::getTargetMember)
                                .eq(TMemberFollow::getFollowMember, mId)
                                .eq(TMemberFollow::getStatus, CommonStatus.NORMAL.getType())
                );
    }


    @Override
    public PageResult<MemberDTO> users(int page, int size, String nikeName, String mobile, Long id, Long min, Long max, LocalDate minDate, LocalDate maxDate, Integer status, String name, String area, String source, Integer autoId) {
        LambdaQueryWrapperX<TMember> wrapper = new LambdaQueryWrapperX<TMember>()
                .eqIfPresent(TMember::getStatus, status == null ? null : status.equals(1) ? 0 : 1)
                .eqIfPresent(TMember::getSource, StringUtils.isBlank(source) ? null : source)
                .eqIfPresent(TMember::getAutoId, autoId)
                .rightLikeIfPresent(TMember::getNickName, nikeName)
                .likeIfPresent(TMember::getMobile, mobile)
                .likeIfPresent(TMember::getName, name)
                .likeIfPresent(TMember::getArea, area)
                .likeIfPresent(TMember::getId, id == null ? "" : id.toString())
                .orderByDesc(TMember::getAddTime);
        //.orderByDesc(TMember::getLastVisitTime);

        if (min != null && max != null) {
            wrapper
                    .ge(TMember::getBalance, min)
                    .le(TMember::getBalance, max);
        }
        if (minDate != null && maxDate != null) {
            wrapper
                    .ge(TMember::getAddTime, LocalDateTime.of(minDate, LocalTime.MIN))
                    .lt(TMember::getAddTime, LocalDateTime.of(maxDate.plusDays(1), LocalTime.MIN));
        }

        Page<TMember> memberPage = memberMapper.selectPage(
                new Page<>(page, size),
                wrapper
        );
        if (CollectionUtils.isEmpty(memberPage.getRecords()))
            return new PageResult<>();

        List<Long> ids = memberPage.getRecords().stream().map(TMember::getId).collect(Collectors.toList());
        List<TPublishOrder> publishOrders = publishOrderMapper.selectList(new LambdaQueryWrapper<TPublishOrder>()
                .select(TPublishOrder::getCategoryId, TPublishOrder::getMId)
                .in(TPublishOrder::getMId, ids)
                .eq(TPublishOrder::getStatus, CommonStatus.NORMAL.getType()));

        Map<Long, List<TPublishOrder>> publishMap = publishOrders.stream().filter(f -> f.getMId() != null).collect(Collectors.groupingBy(TPublishOrder::getMId));
        ImmutableMap<Long, TProductCategory> cateMap = Maps.uniqueIndex(categoryMapper.selectAll(), TProductCategory::getId);
        Set<Long> parentIds = memberPage.getRecords().stream().filter(f -> f.getParentId() != null).map(TMember::getParentId).collect(Collectors.toSet());
        List<TMember> spreadMembers = Lists.newArrayList();

        if (CollectionUtils.isNotEmpty(parentIds))
            spreadMembers = memberMapper.selectList(
                    new LambdaQueryWrapper<TMember>()
                            .select(TMember::getAutoId, TMember::getNickName)
                            .in(TMember::getAutoId, parentIds)
            );
        ImmutableMap<Long, TMember> spreadMemberMaps = Maps.uniqueIndex(spreadMembers, TMember::getAutoId);

        PageResult<MemberDTO> result = new PageResult<MemberDTO>()
                .setCurrent(memberPage.getCurrent())
                .setPages(memberPage.getPages())
                .setSize(memberPage.getSize())
                .setTotal(memberPage.getTotal());

        for (TMember record : memberPage.getRecords()) {
            List<String> cates = Optional
                    .ofNullable(publishMap.get(record.getId()))
                    .map(m ->
                            m.stream()
                                    .map(item -> {
                                        TProductCategory category = cateMap.get(item.getCategoryId());
                                        return category == null ? null : category.getCaption();
                                    })
                                    .filter(ObjectUtils::allNotNull)
                                    .distinct()
                                    .collect(Collectors.toList())
                    ).orElse(Lists.newArrayList());

            result.getRecords().add(
                    new MemberDTO()
                            .setId(record.getId())
                            .setAutoId(record.getAutoId())
                            .setName(record.getName())
                            .setArea(record.getArea())
                            .setNickName(record.getNickName())
                            .setRecommendPerson(spreadMemberMaps.getOrDefault(record.getParentId(), new TMember()).getNickName())
                            .setMobile(record.getMobile())
                            .setBalance(Optional.ofNullable(record.getBalance()).orElse(BigDecimal.ZERO))
                            .setRechargeMoney(Optional.ofNullable(record.getRechargeMoney()).orElse(BigDecimal.ZERO))
                            .setOperateMoney(Optional.ofNullable(record.getOperateMoney()).orElse(BigDecimal.ZERO))
                            .setConsumeMoney(Optional.ofNullable(record.getConsumeMoney()).orElse(BigDecimal.ZERO))
                            .setIncomeMoney(Optional.ofNullable(record.getIncomeMoney()).orElse(BigDecimal.ZERO))
                            .setAddTime(record.getAddTime())
                            .setLastVisitTime(record.getLastVisitTime())
                            .setStatus(record.getStatus().equals(0) ? 1 : 0)
                            .setRemarks(record.getRemarks())
                            .setSource(record.getSource())
                            .setCate(cates)
            );
        }
        return result;
    }

    @Override
    public boolean followMember(String mId, String obj, String type) {
        if ("0".equalsIgnoreCase(type))//0取消关注
            return memberFollowMapper
                    .update(null,
                            new LambdaUpdateWrapper<TMemberFollow>()
                                    .set(TMemberFollow::getStatus, type)
                                    .eq(TMemberFollow::getUnLock, mId + obj)
                    ) == 1;

        operateBlackList(mId, Long.parseLong(obj), CommonStatus.DISABLED.getType());

        return memberFollowMapper.findAndSetFollow(
                new TMemberFollow()
                        .setStatus(Integer.parseInt(type))
                        .setFollowMember(Long.parseLong(mId))
                        .setTargetMember(Long.parseLong(obj))
                        .setUnLock(mId + obj)
        ) > 0;
    }

    @Override
    public boolean isFollowObj(String currentMemberId, String obj) {
        return memberFollowMapper.selectCount(
                new QueryWrapper<>(
                        new TMemberFollow()
                                .setUnLock(currentMemberId + obj)
                                .setStatus(CommonStatus.NORMAL.getType())
                )) == 1;


    }

    @Override
    public Predicate<BindAccParams> bindWx() {
        return bindAccParams -> {
            JSONObject oauth2 = tencentComponent.oauth2(bindAccParams.getCode());
            String openId = oauth2.getString("openid");
            TMember member = memberMapper.selectOne(
                    new LambdaQueryWrapper<TMember>()
                            .select(TMember::getWxOpenId)
                            .eq(TMember::getId, bindAccParams.getMId())
            );
            Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
            Check.state(StringUtils.isNotBlank(member.getWxOpenId()), ExpCode.OPEN_ID_BIND_EXIST);

            return memberMapper.update(null,
                    new LambdaUpdateWrapper<TMember>()
                            .set(TMember::getWxOpenId, openId)
                            .eq(TMember::getId, bindAccParams.getMId())) == 1;

        };

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void memberTrans(final String mId, final String money, String type, String payKey, Function<TransferParams, TransferResult> transInstance) {
        TMember member =
                memberMapper
                        .selectOne(
                                new LambdaQueryWrapper<TMember>()
                                        .select(TMember::getAutoId, TMember::getPayPwd, TMember::getBalance, TMember::getVersion, TMember::getWxOpenId, TMember::getZfbOpenId)
                                        .eq(TMember::getId, mId));
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        Check.state(passwordEncoder.matches(payKey, member.getPayPwd()), ExpCode.PAY_PASSWORD_NOT_MATCHES);
        //提现用户openId
        String toUser =
                PaymentEnum.WX_PAY.getType().equals(type) ? member.getWxOpenId() :
                        PaymentEnum.ALI_PAY.getType().equals(type) ? member.getZfbOpenId() :
                                null;
        //对应提现方式 未绑定openId
        Check.state(StringUtils.isNotBlank(toUser), ExpCode.NOT_BIND_OPEN_ID);
        final BigDecimal balance = member.getBalance();
        BigDecimal operateMoney = new BigDecimal(money);
        final BigDecimal feeScale = new BigDecimal(balanceConfig.getTransScale());
        BigDecimal fee = operateMoney.multiply(feeScale);
        BigDecimal afterBalance = balance.subtract(operateMoney.add(fee));
        if (operateMoney.compareTo(balance) > 0) {
            log.info("提现金额大于可用余额");
            return;
        } else if (operateMoney.compareTo(balance) == 0 || afterBalance.compareTo(BigDecimal.ZERO) < 0) {
            //提现金额  余额全部提现
            fee = balance.multiply(feeScale);
            operateMoney = balance.subtract(fee);
            afterBalance = BigDecimal.ZERO;
        }
        //提交修改会员余额
        int row = memberMapper.update(null,
                new LambdaUpdateWrapper<TMember>()
                        .set(TMember::getBalance, afterBalance)
                        .set(TMember::getVersion, member.getVersion() + 1)
                        .eq(TMember::getId, mId)
                        .eq(TMember::getVersion, member.getVersion()));
        Assert.state(row == 1, "member transfer money update balance exception ");
        //转账金额 = 提现金额 - 提现费用
        String realMoney = PayUtil.getTransAmountByEnv(env, operateMoney, type);
        //转账参数
        TransferParams transferParams = new TransferParams()
                .setDesc("提现")
                .setId("t" + DateUtils.dateyyyyMMdd() + IdWorker.getIdStr())
                .setMoney(realMoney)
                .setType(type)
                .setToUser(toUser);
        //转账调用
        TransferResult transferResult = transInstance.apply(transferParams);
        TMemberBalanceLog memberBalanceLog = new TMemberBalanceLog()
                .setBalance(afterBalance)
                .setBeforeM(balance)
                .setMoney(operateMoney)
                .setFee(fee)
                .setFeeScale(balanceConfig.getTransScale())
                .setMethod(Integer.parseInt(type))
                .setTradeType(BalanceLogEnum.TRANS.getType())
                .setMId(Long.parseLong(mId))
                .setPayTime(LocalDateTime.now())
                .setTradeNo(transferParams.getId())
                .setRechargeType(1);

        try {
            if (transferResult != null && transferResult.getStatus()) {
                //成功
                log.info("trans success mId::{},money::{},method::{}", mId, money, type);
                memberBalanceLog
                        .setTransactionId(transferResult.getTransactionId())
                        .setTips(transferResult.getDesc())
                        .setPrePayId(transferResult.getTradeNO())
                        .setStatus(PayStatusEnum.FINISH.getType());
            } else
                throw new ResponseException(500, "trans fail");

        } catch (ResponseException e) {
            memberBalanceLog
                    .setStatus(PayStatusEnum.NOT.getType())
                    .setTips(transferResult.getErrCode());
            log.info("trans fail mId::{},money::{},method::{}", mId, money, type);
            throw e;
        } finally {
            //不管是否成功 保存提现记录
            Integer logRow = ((MemberServiceImpl) AopContext.currentProxy()).saveMemberBalanceLog(memberBalanceLog);
            if (logRow != 1)
                log.error("BalanceLog 添加失败::{}", memberBalanceLog);
        }
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @Override
    public Integer saveMemberBalanceLog(TMemberBalanceLog log) {
        return memberBalanceLogMapper.insert(log);
    }

    @Override
    public TGuest guestLogin(String deviceId) {
        TGuest guest = guestMapper.selectOne(
                new QueryWrapper<>(
                        new TGuest().setDeviceId(deviceId)));

        if (guest == null) {
            guest = new TGuest()
                    .setDeviceId(deviceId)
                    .setName("guest_" + (guestMapper.selectCount(new QueryWrapper<>()) + 1))
                    .setConvertMember(0);

            if (guestMapper.insert(guest) != 1)
                throw new LoginException(ExpCode.LOGIN_GUEST_FAIL.getCode(), ExpCode.LOGIN_GUEST_FAIL.getMsg());

            return guest;

        } else
            return guest;

    }

    @Override
    public void saveMemberVisit(String currentMember, String targetMember) {
        if (StringUtils.isBlank(currentMember) || "-1".equalsIgnoreCase(currentMember))
            return;
        String id = currentMember + targetMember;
        TMemberVisit memberVisit = memberVisitMapper.selectById(id);
        if (memberVisit == null) {
            if (memberVisitMapper.insert(
                    new TMemberVisit()
                            .setId(id)
                            .setCurrentMember(Long.parseLong(currentMember))
                            .setTargetMember(Long.parseLong(targetMember))) != 1) {
                log.info("saveMemberVisit fail");
            }
        }
    }

    @Override
    public List<TMemberAlbum> getMemberAlbumsByMId(String mId) {
        return memberAlbumMapper.selectList(
                new LambdaQueryWrapper<TMemberAlbum>()
                        .select(TMemberAlbum::getOrderNum, TMemberAlbum::getMId, TMemberAlbum::getId, TMemberAlbum::getUrl)
                        .eq(TMemberAlbum::getMId, mId)
                        .eq(TMemberAlbum::getStatus, CommonStatus.NORMAL.getType())
                        .eq(TMemberAlbum::getType, 2) //2身份认证生活照
        )

                .stream()
                .map(m -> StringUtils.isBlank(m.getUrl()) ? m : m.setUrl(ossConfig.getHostname() + "/" + m.getUrl()))
                .limit(3)
                .sorted(Comparator.comparing(TMemberAlbum::getOrderNum)).collect(Collectors.toList());
    }

    @Transactional
    @Override
    public boolean addMemberAsk(String mId, String content, String img) {
        long id = Long.parseLong(mId);
        String nickName = getNickNameById(id);
        return memberAskMapper.insert(new TMemberAsk()
                .setContent(content)
                .setMId(id)
                .setImg(img)
                .setName(nickName)) == 1;
    }

    @Override
    public boolean addMemberReport(String currentMId, String reason, String targetMId, String content, String img) {
        long currentId = Long.parseLong(currentMId);
        long tagId = Long.parseLong(targetMId);
        String currentNickName = getNickNameById(currentId);
        String targetNickName = getNickNameById(tagId);
        return memberReportMapper.insert(new TMemberReport()
                .setImg(StringUtils.isBlank(img) ? img : img.replaceAll(ossConfig.getHostname() + "/", ""))
                .setSourceId(currentId)
                .setSourceName(currentNickName)
                .setTargetId(tagId)
                .setTargetName(targetNickName)
                .setReportContent(strToList(",", reason).toString() + ":" + content)) == 1;

    }

    @Transactional
    @Override
    public boolean editMemberInfo(Long mId, String imgUrl, String nickName, Integer height, String birthday,
                                  String area, String job, String sign, Integer age, Integer gender) {
        //存在相同昵称，则编辑失败
        if (StringUtils.isNotEmpty(nickName)) {
            TMember nickNameIsExists =
                    memberMapper
                            .selectOne(
                                    new LambdaQueryWrapper<TMember>()
                                            .select(TMember::getNickName)
                                            .eq(TMember::getNickName, nickName)
                                            .notIn(TMember::getId, mId)
                            );
            if (nickNameIsExists != null) {
                return false;
            }
        }

        birthday = StringUtils.isBlank(birthday) ? "" : birthday.replace("-", "/");
        Integer computeAge = StringUtils.isBlank(birthday) ? null : LocalDate.now().getYear() - Parse.toInt(birthday.substring(0, 4), 2000);
        age = age == null ? computeAge : age;
        boolean vip = isVip(mId.toString());
        if (!vip) {
            String nickname = getNickNameById(mId);
            if (!nickname.equals(nickName)){
                if (redis.hexists(CacheKey.DATA.updNickname, mId)) {
                    nickName = null;
                } else
                    redis.hSet(CacheKey.DATA.updNickname, mId, nickname);
            }



        }
        int row = memberMapper

                .update(null,
                        new LambdaUpdateWrapper<TMember>()
                                .set(StringUtils.isNotBlank(imgUrl), TMember::getImgUrl, StringUtils.isBlank(imgUrl) ? imgUrl : imgUrl.replace(ossConfig.getHostname() + "/", ""))
                                .set(StringUtils.isNotBlank(nickName), TMember::getNickName, nickName)
                                .set(StringUtils.isNotBlank(String.valueOf(height)), TMember::getHeight, height)
                                .set(StringUtils.isNotBlank(birthday), TMember::getBirthday, birthday)
                                .set(StringUtils.isNotBlank(area), TMember::getArea, area)
                                .set(StringUtils.isNotBlank(job), TMember::getJob, job)
                                .set(StringUtils.isNotBlank(sign), TMember::getSign, sign)
                                .set(age != null, TMember::getAge, age)
                                .set(gender != null, TMember::getGender, gender)
                                .eq(TMember::getId, mId)

                );
        if (row == 1)
            tencentComponent.importImAccount(
                    new TMember()
                            .setId(mId)
                            .setNickName(nickName)
                            .setImgUrl(imgUrl));
        return row == 1;

    }

    @Transactional
    @Override
    public boolean updAlbums(Long mId, String imgUrl) {
        memberAlbumMapper.delete(new QueryWrapper<>(new TMemberAlbum().setMId(mId)));
        List<TMemberAlbum> albums = new ArrayList<>();
        String[] split = imgUrl.replaceAll("，", ",").split(",");
        for (int i = 0; i < split.length; i++) {
            TMemberAlbum album = new TMemberAlbum()
                    .setMId(mId)
                    .setOrderNum(i)
                    .setUrl(StringUtils.isBlank(split[i]) ? split[i] : split[i].replace(ossConfig.getHostname() + "/", ""))
                    .setAddTime(LocalDateTime.now())
                    .setType(0)
                    .setStatus(CommonStatus.NORMAL.getType());
            albums.add(album);
        }

        return memberAlbumMapper.insertBatchSomeColumn(albums) == split.length;
    }

    @Override
    public boolean identityChecked(String mId, String name, Integer gender, String birthday, String area, String idCode, String urls) {
        TMember member = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getAutoId, TMember::getIdentity, TMember::getIdStatus)
                        .eq(TMember::getId, mId)
        );
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        Check.state(member.getIdStatus() < AuthFaceEnum.PROCESSING.getCode(), ExpCode.OPEN_ID_BIND_EXIST);
        return memberMapper.update(null,
                new LambdaUpdateWrapper<TMember>()
                        .set(TMember::getName, name)
                        .set(TMember::getGender, gender)
                        .set(TMember::getBirthday, birthday)
                        .set(TMember::getAge, LocalDate.now().getYear() - Parse.toInt(idCode.substring(6, 10), 2000))
                        .set(TMember::getArea, area)
                        .set(TMember::getIdentity, idCode)
                        .set(TMember::getIdUrl, urls)
                        .set(TMember::getIdStatus, CommonStatus.NORMAL.getType())
                        .eq(TMember::getId, Long.valueOf(mId))) == 1;

    }

    @Override
    public boolean addMember(TMember member) {
        Check.notNull(member, ExpCode.PARAMS_ILLEGAL);
        if (StringUtils.isNotBlank(member.getPayPwd()))
            member.setPayPwd(passwordEncoder.encode(member.getPayPwd()));
        if (StringUtils.isNotBlank(member.getPassword()))
            member.setPassword(passwordEncoder.encode(member.getPassword()));


        member.setId(IdWorker.getId());
        return memberMapper.insert(member) == 1;
    }

    @Override
    public boolean changeStatus(String mId, String status) {
        return memberMapper
                .update(
                        null,
                        new LambdaUpdateWrapper<TMember>()
                                .set(StringUtils.isNotBlank(mId) && StringUtils.isNotBlank(status), TMember::getStatus, "0".equals(status) ? "1" : "0")
                                .eq(TMember::getId, mId)
                ) == 1;
    }

    @Override
    public SearchMemberVo search(String mId, String kw) {
        Page<TMember> page = new Page<>(1, 5);
        //kw ==null searchInfo =null
        List<MemberInfoDTO> searchInfo = null;

        if (StringUtils.isNotBlank(kw)) {
            //匹配5条关键字会员信息结果
            Page<TMember> members = memberMapper.selectPage(page,
                    new LambdaQueryWrapper<TMember>()
                            .select(TMember::getId, TMember::getNickName, TMember::getImgUrl, TMember::getAutoId, TMember::getServiceLevel)
                            .like(TMember::getNickName, kw)
                            .or().like(TMember::getAutoId, kw)
            );
            //查询结果的 会员ids
            String ids = members
                    .getRecords()
                    .stream()
                    .map(m -> m.getId() + "")
                    .filter(StringUtils::isNotBlank)
                    .collect(Collectors.joining(","));
            //拼接关注ids
            String followIds = members
                    .getRecords()
                    .stream()
                    .map(m -> {
                        if (StringUtils.isBlank(mId))
                            return null;
                        return mId + m.getId();
                    })
                    .filter(f -> f != null)
                    .collect(Collectors.joining(","));
            //当前用户关注map k = currMid + targetMid value = 1 or null or 0
            if (StringUtils.isBlank(followIds)) {
                followIds = "-1";
            }
            Map<String, TMemberFollow> followMap = CollectionUtils.isEmpty(page.getRecords()) ? new HashMap<>() : memberFollowMapper
                    .selectIsFollow(followIds)
                    .stream()
                    .collect(Collectors.toMap(TMemberFollow::getUnLock, f -> f));
            //当前用户关注map k = targetMid value = count
            if (StringUtils.isBlank(ids))
                ids = "-1";

            Map<Long, TMemberFollow> fensMap = CollectionUtils.isEmpty(page.getRecords()) ? new HashMap<>() :
                    memberFollowMapper
                            .selectFensi(ids)
                            .stream()
                            .collect(Collectors.toMap(TMemberFollow::getTargetMember, f -> f));

            searchInfo =
                    members.getRecords()
                            .stream()
                            .map(m -> {
                                        TMemberFollow follow = followMap.get(mId + m.getId());
                                        TMemberFollow fensi = fensMap.get(m.getId());
                                        Integer fens = fensi == null ? 0 : fensi.getFollowMember().intValue();
                                        return new MemberInfoDTO()
                                                .setNickName(m.getNickName())
                                                .setId(m.getId())
                                                .setAutoId(m.getAutoId())
                                                .setImgUrl(StringUtils.isBlank(m.getImgUrl()) ? null : ossConfig.getHostname() + "/" + m.getImgUrl())
                                                .setFollower(fens)
                                                .setFollow(follow != null && !follow.getFollowMember().equals(0L))
                                                .setServiceLevel(m.getServiceLevel());
                                    }
                            )
                            .sorted(Comparator.comparing(MemberInfoDTO::getServiceLevel).reversed()
                                    .thenComparing(MemberInfoDTO::getFollower).reversed())
                            .collect(Collectors.toList());
        }


        List<MemberInfoDTO> recommendMember = memberMapper.selectRecommendMember(mId);
        String recommendIds = recommendMember
                .stream()
                .map(m -> m.getId() + "")
                .collect(Collectors.joining(","));
        List<TMemberVip> vips = vipMapper.selectMemberVipEndTime(StringUtils.isBlank(recommendIds) ? "-1" : recommendIds);
        ImmutableMap<Long, TMemberVip> vMaps = Maps.uniqueIndex(vips, TMemberVip::getMId);
        recommendMember.stream()
                .forEachOrdered(f ->
                        f
                                .setVip(
                                        vMaps.get(f.getId()) != null &&
                                                LocalDateTime.now().isBefore(vMaps.get(f.getId()).getEndTime()))
                                .setImgUrl(StringUtils.isBlank(f.getImgUrl()) ? null : ossConfig.getHostname() + "/" + f.getImgUrl())
                );
        return new SearchMemberVo()
                .setResult(searchInfo)
                .setRecommend(recommendMember);
    }

    @Override
    public boolean isVip(String targetMember) {
        return vipMapper.selectCount(
                new LambdaQueryWrapper<TMemberVip>()
                        .eq(TMemberVip::getMId, targetMember)
                        .ge(TMemberVip::getEndTime, LocalDateTime.now())

        ) > 0;
    }

    @Override
    public PageResult<BalanceChangeLog> memberBalanceLog(int pageNo, int pageSize, String mId, LocalDate beginTme, LocalDate endTime, String type) {
        Page<TMemberBalanceLog> pages = memberBalanceLogMapper
                .selectPage(
                        new Page<>(pageNo, pageSize),
                        new LambdaQueryWrapper<TMemberBalanceLog>()
                                .select(TMemberBalanceLog::getMId, TMemberBalanceLog::getId, TMemberBalanceLog::getTips, TMemberBalanceLog::getTradeNo, TMemberBalanceLog::getTradeType,
                                        TMemberBalanceLog::getBeforeM, TMemberBalanceLog::getMethod, TMemberBalanceLog::getMoney, TMemberBalanceLog::getFee, TMemberBalanceLog::getFeeScale, TMemberBalanceLog::getBalance, TMemberBalanceLog::getAddTime)
                                .eq(TMemberBalanceLog::getStatus, CommonStatus.NORMAL.getType())
                                .eq(TMemberBalanceLog::getMId, Long.valueOf(mId))
                                .eq(StringUtils.isNotBlank(type), TMemberBalanceLog::getTradeType, type)
                                .ge(beginTme != null && endTime != null, TMemberBalanceLog::getAddTime, LocalDateTime.of(beginTme == null ? LocalDate.now() : beginTme, LocalTime.MIN))
                                .lt(beginTme != null && endTime != null, TMemberBalanceLog::getAddTime, LocalDateTime.of(endTime == null ? LocalDate.now() : endTime.plusDays(1), LocalTime.MIN))
                                .orderByDesc(TMemberBalanceLog::getAddTime)
                );
        String nickName = getNickNameById(Long.parseLong(mId));
        List<BalanceChangeLog> res =
                pages
                        .getRecords()
                        .stream()
                        .map(m ->
                                new BalanceChangeLog()
                                        .setId(String.valueOf(m.getId()))
                                        .setTradeNo(m.getTradeNo())
                                        .setNickName(nickName)
                                        .setBeforeMoney(m.getBeforeM())
                                        .setMoney(m.getMoney().add(m.getFee()))
                                        .setAfterMoney(m.getBalance())
                                        .setCompanyGet(m.getFee())
                                        .setTips(
                                                (PaymentEnum.WX_PAY.getType().equalsIgnoreCase(String.valueOf(m.getMethod())) ? "微信-" :
                                                        PaymentEnum.ALI_PAY.getType().equalsIgnoreCase(String.valueOf(m.getMethod())) ? "支付宝-" : "")
                                                        + m.getTips()
                                        ).setDate(DateUtils.getLocalDateTimeStr(m.getAddTime(), AppConst.DATE_SHOW_FORMAT))
                        )
                        .collect(Collectors.toList());

        return new PageResult<BalanceChangeLog>()
                .setCurrent(pages.getCurrent())
                .setRecords(res)
                .setPages(pages.getPages())
                .setTotal(pages.getTotal())
                .setSize(pages.getSize());

    }

    @Override
    public MemberDetailDTO getMemberDetailsById(String mId) {
        TMember res = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getIdentity, TMember::getMobile, TMember::getGender, TMember::getName, TMember::getArea, TMember::getIdUrl)
                        .eq(TMember::getId, mId)
        );
        MemberDetailDTO ret = new MemberDetailDTO();
        BeanUtils.copyProperties(res, ret);
        return ret.setIdUrls(strToList(",", res.getIdUrl()).stream().map(url -> StringUtils.isBlank(url) ? "" : ossConfig.getHostname() + '/' + url).collect(Collectors.toList()));
    }

    @Override
    public boolean saveMemberPassword(String mId, String password) {
        TMember member =
                memberMapper.selectOne(
                        new LambdaQueryWrapper<TMember>()
                                .select(TMember::getAutoId, TMember::getPassword)
                                .eq(TMember::getId, mId)
                );
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        Check.state(StringUtils.isBlank(member.getPassword()), ExpCode.PASSWORD_EXISTS);
        return memberMapper.updateById(member.setPassword(passwordEncoder.encode(password))) == 1;
    }

    @Override
    public boolean updMemberPassword(String mId, String oldPassword, String newPassword) {
        TMember member =
                memberMapper.selectOne(
                        new LambdaQueryWrapper<TMember>()
                                .select(TMember::getAutoId, TMember::getPassword)
                                .eq(TMember::getId, mId)
                );
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        Check.state(passwordEncoder.matches(oldPassword, member.getPassword()), ExpCode.PASSWORD_NOT_MATCHES);
        return memberMapper.updateById(member.setPassword(passwordEncoder.encode(newPassword))) == 1;
    }

    /**
     * 后台重置密码/修改密码
     *
     * @param member
     * @return
     */
    @Override
    public boolean resetMemberPassword(TMember member) {
        return memberMapper.updateById(member) == 1;
    }

    @Override
    public MemberDashboardData memberCacheInfo(String id) {
        TMember member = memberMapper
                .selectOne(
                        new LambdaQueryWrapper<TMember>()
                                .select(TMember::getAutoId, TMember::getId, TMember::getNickName, TMember::getParentId, TMember::getGender, TMember::getMobile, TMember::getBalance,
                                        TMember::getServiceLevel, TMember::getImgUrl, TMember::getBirthday, TMember::getArea, TMember::getSign, TMember::getAge,
                                        TMember::getJob, TMember::getHeight, TMember::getPassword, TMember::getWxOpenId, TMember::getZfbOpenId, TMember::getPayPwd,
                                        TMember::getIdentity, TMember::getIosToken, TMember::getIosToken, TMember::getEnableOrder, TMember::getEnableDynamic, TMember::getEnableFollower,
                                        TMember::getMsgChat, TMember::getSecurityScore, TMember::getMsgDynamic, TMember::getMsgOrder, TMember::getStatus, TMember::getFaceStatus, TMember::getIdStatus)
                                .eq(TMember::getId, id)
                );
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        Check.state(!MemberStatusEnum.DISABLED.getCode().equals(member.getStatus()), ExpCode.ACCOUNT_DISABLED);
        Check.state(!MemberStatusEnum.LOGOUT.getCode().equals(member.getStatus()), ExpCode.MEMBER_NOT_EXIST);
        String password = member.getPassword();
        String wxOpenId = member.getWxOpenId();
        String zfbOpenId = member.getZfbOpenId();
        String payPwd = member.getPayPwd();
        String identity = member.getIdentity();
        if (StringUtils.isBlank(password) || "0".equals(password))
            member.setPassword("false");
        else
            member.setPassword("true");

        if (StringUtils.isBlank(wxOpenId) || "0".equals(wxOpenId))
            member.setWxOpenId("false");
        else
            member.setWxOpenId("true");

        if (StringUtils.isBlank(zfbOpenId) || "0".equals(zfbOpenId))
            member.setZfbOpenId("false");
        else
            member.setZfbOpenId("true");

        if (StringUtils.isBlank(payPwd) || "0".equals(payPwd))
            member.setPayPwd("false");
        else
            member.setPayPwd("true");

        if (StringUtils.isBlank(identity) || "0".equals(identity))
            member.setIdentity("false");
        else {
            if (member.getIdStatus() > 0)
                member.setIdentity("true");
        }


        MemberDashboardData res = getDashboardData(Long.parseLong(id));
        BeanUtils.copyProperties(member, res);
        res.setIosToken(StringUtils.isBlank(member.getIosToken()) ? "false" : "true");
        res.setAndroidToken(StringUtils.isBlank(member.getAndroidToken()) ? "false" : "true");
        if (StringUtils.isNotBlank(member.getImgUrl()))
            res.setImgUrl(ossConfig.getHostname() + "/" + member.getImgUrl());
        res.setHistoryCount(redis.zCard(CacheKey.USER.userHistory + id));
        if (res.isVip()) {
            Page<TMemberVip> tMemberVipPage = vipMapper.selectPage(new Page<>(1, 1),
                    new LambdaQueryWrapper<TMemberVip>()
                            .eq(TMemberVip::getMId, id)
                            .orderByDesc(TMemberVip::getEndTime)
            );
            res.setVipTime(tMemberVipPage.getTotal() == 0 ? "" : DateUtils.getLocalDateTimeStr(tMemberVipPage.getRecords().get(0).getEndTime()));
        }

        return res;
    }

    @Override
    public boolean savePayPwd(String mId, String payPassword) {
        TMember member = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getPayPwd, TMember::getAutoId)
                        .eq(TMember::getId, mId)
        );
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        Check.state(StringUtils.isBlank(member.getPayPwd()), ExpCode.PASSWORD_EXISTS);
        member.setPayPwd(passwordEncoder.encode(payPassword));
        return memberMapper.updateById(member) == 1;
    }

    @Override
    public boolean updPayPwd(String mId, String oldPayPassword, String newPayPassword) {
        TMember member = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getPayPwd, TMember::getAutoId)
                        .eq(TMember::getId, mId)
        );
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        Check.state(passwordEncoder.matches(oldPayPassword, member.getPayPwd()), ExpCode.PASSWORD_NOT_MATCHES);
        return memberMapper.updateById(member.setPayPwd(passwordEncoder.encode(newPayPassword))) == 1;
    }

    @Override
    public void operateBlackList(String currentId, Long obj, Integer status) {
        if (status == 0) {
            blackListMapper.update(null,
                    new LambdaUpdateWrapper<TMemberBlackList>()
                            .set(TMemberBlackList::getStatus, status)
                            .eq(TMemberBlackList::getUnLock, currentId + obj)
            );
            return;
        }
        blackListMapper.findAndSetBlackList(
                new TMemberBlackList()
                        .setMId(Long.parseLong(currentId))
                        .setBlackObj(obj)
                        .setUnLock(currentId + obj)
                        .setStatus(status)
        );
    }

    @Override
    public PageResult<BlackListDTO> blackList(String id, int pageNo, int pageSize) {
        Page<TMemberBlackList> page = blackListMapper.selectPage(new Page<>(pageNo, pageSize),
                new LambdaQueryWrapper<TMemberBlackList>()
                        .select(TMemberBlackList::getBlackObj)
                        .eq(TMemberBlackList::getMId, id)
                        .eq(TMemberBlackList::getStatus, CommonStatus.NORMAL.getType())
        );

        List<Long> ids = page
                .getRecords()
                .stream()
                .map(TMemberBlackList::getBlackObj)
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(ids))
            return new PageResult<>();

        List<BlackListDTO> records = memberMapper
                .selectList(
                        new LambdaQueryWrapper<TMember>()
                                .select(TMember::getNickName, TMember::getId, TMember::getImgUrl)
                                .in(TMember::getId, ids))
                .stream()
                .map(m -> new BlackListDTO().setImgUrl(StringUtils.isBlank(m.getImgUrl()) ? null : ossConfig.getHostname() + "/" + m.getImgUrl()).setMId(m.getId() + "").setNickName(m.getNickName()))
                .collect(Collectors.toList());

        return new PageResult<BlackListDTO>()
                .setSize(page.getSize())
                .setTotal(page.getTotal())
                .setRecords(records)
                .setPages(page.getPages())
                .setCurrent(page.getCurrent());
    }

    @Override
    public Map<String, Long> followAndBlackList(String currentMember, String targetMember) {
        return memberFollowMapper.followAndBlackList(currentMember + targetMember);

    }


    @Override
    public boolean changeSeeForStatus(String id, String type, Integer status) {
        try {
            return memberMapper
                    .update(null,
                            new LambdaUpdateWrapper<TMember>()
                                    .set(status != null,
                                            AppConst.ENABLE_ORDER_TYPE.equals(type) ? TMember::getEnableOrder :
                                                    AppConst.ENABLE_DYNAMIC_TYPE.equals(type) ? TMember::getEnableDynamic :
                                                            AppConst.ENABLE_FOLLOWER_TYPE.equals(type) ? TMember::getEnableFollower : null,

                                            status)
                                    .eq(TMember::getId, id)
                    ) == 1;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public boolean getMemberByColumn(String column, String value) {
        LambdaQueryWrapper<TMember> wrapper = new LambdaQueryWrapper<TMember>()
                .select(TMember::getId, TMember::getMobile, TMember::getNickName, TMember::getName);
        if (column.equals("mobile")) {
            wrapper.eq(TMember::getMobile, value);
        }
        if (column.equals("nickName")) {
            wrapper.eq(TMember::getNickName, value);
        }
        if (column.equals("name")) {
            wrapper.eq(TMember::getName, value);
        }
        return memberMapper.selectList(wrapper).size() > 0;
    }


    @Override
    public Predicate<BindAccParams> bindZfb() {
        return bindAccParams -> {
            String zfbOpenId = null;
            try {
                zfbOpenId = paymentComponent.getAliUserId(bindAccParams.getCode());
            } catch (AlipayApiException e) {
                e.printStackTrace();
            }
            Check.state(StringUtils.isNotBlank(zfbOpenId), ExpCode.OPEN_ID_BIND_FAIL);
            TMember member = memberMapper.selectOne(
                    new LambdaQueryWrapper<TMember>()
                            .select(TMember::getZfbOpenId)
                            .eq(TMember::getId, bindAccParams.getMId())
            );
            Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
            Check.state(StringUtils.isBlank(member.getZfbOpenId()), ExpCode.OPEN_ID_BIND_EXIST);
            return memberMapper.update(
                    null,
                    new LambdaUpdateWrapper<TMember>()
                            .set(TMember::getZfbOpenId, zfbOpenId)
                            .eq(TMember::getId, bindAccParams.getMId())
            ) == 1;
        };

    }

    @Override
    public TransInfoDTO computeTransInfo(String id, String amount) {
        TMember member = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getBalance)
                        .eq(TMember::getId, id)
        );
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        BigDecimal balance = member.getBalance();
        //用户发起的提现金额
        BigDecimal money = new BigDecimal(amount);
        if (money.compareTo(balance) > 0)
            throw new ResponseException(ExpCode.TRANS_MONEY_NOTSUPORT.getCode(), ExpCode.TRANS_MONEY_NOTSUPORT.getMsg());
        //提现费率
        BigDecimal feeScale = new BigDecimal(balanceConfig.getTransScale());
        //手续费
        BigDecimal fee = money.multiply(feeScale);

        BigDecimal transMoney = money;
        //展示提现总额
        BigDecimal showMoney = money.add(fee);
        if (balance.compareTo(showMoney) < 0) {
            //余额小于 提现+手续费  提现金额 = 余额
            fee = balance.multiply(feeScale);
            transMoney = balance;
            showMoney = balance;
        }
        //余额大于提现总额
        return new TransInfoDTO()
                .setMoney(transMoney.toString())
                .setFee(fee)
                .setShowMoney(showMoney.setScale(2, 5).toString())
                .setFeeScale(feeScale.multiply(AppConst.b100).setScale(1, 5) + "%");
    }

    @Override
    public MemberShowInfo getMemberShowInfoById(Long mId) {
        TMember member = memberMapper.selectOne(

                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getArea, TMember::getAutoId, TMember::getGender, TMember::getNickName, TMember::getImgUrl, TMember::getServiceLevel)
                        .eq(TMember::getId, mId)
        );

        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);

        return new MemberShowInfo()
                .setMId(String.valueOf(mId))
                .setArea(parseArea(member.getArea()))
                .setImgUrl(StringUtils.isBlank(member.getImgUrl()) ? null : ossConfig.getHostname() + "/" + member.getImgUrl())
                .setServiceLevel(member.getServiceLevel())
                .setNickName(member.getNickName())
                .setAutoId(member.getAutoId())
                .setGender(member.getGender());
    }

    @Override
    public boolean collectPublishOrder(String id, String publishId, Integer status) {
        return collectOrderMapper.findOrSetCollectOrder(new TCollectOrder()
                .setMId(Long.parseLong(id))
                .setPublishOrderId(Long.parseLong(publishId))
                .setUnLock(id + publishId)
                .setStatus(status)
        ) > 0;

    }

    @Override
    public PageResult<MeFollowersDTO> getMyFollowersDetail(String id, int pageNo, int pageSize) {
        /*Page<TMember> page = memberMapper.selectPage(new Page<>(pageNo, pageSize),
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getId, TMember::getNickName, TMember::getImgUrl)
                        .exists("select 1 from t_member_follow f where " +
                                "f.target_member ={0} and status = {1}  and f.follow_member =t_member.id ", id, 1)
                        .orderByDesc(TMember::getAutoId));*/
        Page<MeFollowersDTO> page = memberFollowMapper.selectMyFollowers(new Page<>(pageNo, pageSize), id);

        return new PageResult<MeFollowersDTO>()
                .setSize(page.getSize())
                .setPages(page.getPages())
                .setCurrent(page.getCurrent())
                .setTotal(page.getTotal())
                .setRecords(page.getRecords()
                        .stream()
                        .map(m -> m
                                .setImageUrl(StringUtils.isBlank(m.getImageUrl()) ? m.getImageUrl() : ossConfig.getHostname() + "/" + m.getImageUrl())
                                .setTips(AppConst.FOLLOW_TIPS)
                        )
                        .collect(Collectors.toList())
                );
    }

    @Override
    public PageResult<MeFollowersDTO> getMyFollowDetail(String id, int pageNo, int pageSize) {
        Page<MeFollowersDTO> res = memberFollowMapper.selectMyFollowDetails(new Page<>(pageNo, pageSize), id);
        res.getRecords().forEach(f ->
                f
                        .setTips(f.getTips().equals("0") ? "" : AppConst.FOLLOW_TIPS)
                        .setImageUrl(StringUtils.isBlank(f.getImageUrl()) ? null : ossConfig.getHostname() + "/" + f.getImageUrl())
                        .setFollow(true)
        );
        return new PageResult<MeFollowersDTO>()
                .setRecords(res.getRecords())
                .setTotal(res.getTotal())
                .setPages(res.getPages())
                .setSize(res.getSize())
                .setCurrent(res.getCurrent());

    }

    @Override
    public PageResult<FollowOrderDTO> getMyCollectOrderList(String id, int pageNo, int pageSize) {
        Page<FollowOrderDTO> res = collectOrderMapper.selectCollectOrderListByMId(new Page<>(pageNo, pageSize), id);
        ImmutableMap<Long, TProductCategory> cates = Maps.uniqueIndex(categoryMapper.selectAll(), TProductCategory::getId);
        res.getRecords().forEach(f -> {
            TProductCategory category = cates.get(Long.parseLong(f.getCategory()));
            f.setCategory(category == null ? null : category.getCaption());
            f.setImgUrl(StringUtils.isBlank(f.getImgUrl()) ? f.getImgUrl() : ossConfig.getHostname() + "/" + f.getImgUrl());
        });
        return new PageResult<FollowOrderDTO>()
                .setCurrent(res.getCurrent())
                .setSize(res.getSize())
                .setPages(res.getPages())
                .setTotal(res.getTotal())
                .setRecords(res.getRecords());
    }

    @Override
    public PageResult<MemberDynamicDTO> getMyZanDynamicList(String id, int pageNo, int pageSize) {
        String imgPre = ossConfig.getHostname() + "/";
        Page<Map<String, Object>> res = dynamicFollowMapper.selectFollowDynamicListByMId(new Page<>(pageNo, pageSize), id);

        List<MemberDynamicDTO> ret =
                res
                        .getRecords()
                        .stream()
                        .map(m -> {
                            Map<String, String> map = Maps.transformEntries(m, (k, v) -> String.valueOf(v));
                            MemberShowInfo member = new MemberShowInfo();
                            MemberDynamicDTO dto = new MemberDynamicDTO()
                                    .setMember(member)
                                    .setItem(map.get("imgs") == null ? null
                                            : strToList(",", map.get("imgs")).stream().filter(StringUtils::isNotBlank)
                                            .map(url -> new TMemberDynamicFile().setUrl(imgPre + url))
                                            .collect(Collectors.toList()))
                                    .setFollower(!"0".equals(map.get("follower")))
                                    .setDianzan(true);

                            member.setNickName(map.get("nick_name"))
                                    .setImgUrl(StringUtils.isBlank(map.get("img_url")) ? null : imgPre + map.get("img_url"))
                                    .setServiceLevel(Integer.parseInt(map.get("service_level")))
                                    .setMId(map.get("mId"));
                            dto.setId(Long.parseLong(map.get("id")))
                                    .setTitle(map.get("title"))
                                    .setFollow(Integer.parseInt(map.get("follow")))
                                    .setComment(Integer.parseInt(map.get("comment")));
                            return dto;

                        })
                        .collect(Collectors.toList());

        return new PageResult<MemberDynamicDTO>()
                .setTotal(res.getTotal())
                .setPages(res.getPages())
                .setSize(res.getSize())
                .setCurrent(res.getCurrent())
                .setRecords(ret);
    }

    @Override
    public boolean changeMsgNoticeStatus(String id, String type, Integer status) {
        try {
            return memberMapper
                    .update(null,
                            new LambdaUpdateWrapper<TMember>()
                                    .set(status != null,
                                            AppConst.MSG_NOTICE_ORDER.equals(type) ? TMember::getMsgOrder :
                                                    AppConst.MSG_NOTICE_CHAT.equals(type) ? TMember::getMsgChat :
                                                            AppConst.MSG_NOTICE_DYNAMIC.equals(type) ? TMember::getMsgDynamic : null,

                                            status)
                                    .eq(TMember::getId, id)
                    ) == 1;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 用户注销 如果存在 手机 1替换* wx zfb openid添加'_'区分
     *
     * @param idForm
     * @return
     */
    @Transactional
    @Override
    public boolean updateMember(String id, String autoId) {
        TMember member = memberMapper.selectById(autoId);
        if (member == null)
            member = memberMapper.selectOne(new QueryWrapper<>(new TMember().setId(Parse.toLong(id))));
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        if (MemberStatusEnum.LOGOUT.getCode().equals(member.getStatus()))
            return true;
        //检查金额大于1元注销不通过
        Check.state(BigDecimal.ONE.compareTo(member.getBalance()) > 0, ExpCode.LOGOUT_BALANCE_LIMIT);
        //检查支付订单 存在未完成订单 注销不通过
        Integer buyItCount
                = orderMapper
                .selectCount(new LambdaQueryWrapper<C2cOrder>()
                        .eq(C2cOrder::getMId, member.getId())
                        .eq(C2cOrder::getPayStatus, PayStatusEnum.FINISH.getType())
                        .lt(C2cOrder::getOrderStatus, OrderStatusEnum.FINISH.getStatus())
                );
        Check.state(buyItCount == 0, ExpCode.LOGOUT_ORDER_LIMIT);
        //检查发单 存在发单未完成 注销不通过
        Integer publishCount = orderMapper
                .selectCount(new LambdaQueryWrapper<C2cOrder>()
                        .exists("select 1 from t_publish_order  p where m_id ={0} and p.id = c2c_order.publish_order_id", member.getId())
                        .eq(C2cOrder::getPayStatus, PayStatusEnum.FINISH.getType())
                        .lt(C2cOrder::getOrderStatus, OrderStatusEnum.FINISH.getStatus()));
        Check.state(publishCount == 0, ExpCode.LOGOUT_ORDER_LIMIT);

        TMember tMember = new TMember();
        tMember.setMobile(member.getMobile().replaceAll("1", "*"));
        publishOrderMapper.update(null,
                new LambdaUpdateWrapper<TPublishOrder>()
                        .set(TPublishOrder::getStatus, PublishOrderEnum.DEL.getStatus())
                        .eq(TPublishOrder::getMId, member.getId()));
        return memberMapper.update(null,
                new LambdaUpdateWrapper<TMember>()
                        .set(TMember::getStatus, MemberStatusEnum.LOGOUT.getCode())
                        .set(StringUtils.isNotBlank(member.getMobile()), TMember::getMobile, (member.getMobile() + "").replaceAll("1", "*"))
                        .set(StringUtils.isNotBlank(member.getWxOpenId()), TMember::getWxOpenId, member.getWxOpenId() + "_")
                        .set(StringUtils.isNotBlank(member.getZfbOpenId()), TMember::getZfbOpenId, member.getZfbOpenId() + "_")
                        .set(StringUtils.isNotBlank(member.getIosToken()), TMember::getIosToken, member.getIosToken() + "_")
                        .eq(StringUtils.isBlank(autoId) ? TMember::getId : TMember::getAutoId, StringUtils.isBlank(autoId) ? id : autoId)

        ) == 1;

    }

    @Override
    public boolean bindPhone(String id, String mobile, String code) {
        Integer row = memberMapper.selectCount(new LambdaQueryWrapper<TMember>().eq(TMember::getMobile, mobile));
        Check.state(row == 0, ExpCode.PHONE_EXISTS);
        TMember member = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getMobile, TMember::getAutoId)
                        .eq(TMember::getId, id)
        );
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        //Check.state(StringUtils.isBlank(member.getMobile()), ExpCode.PHONE_IS_BIND);
        authPhoneCode(mobile, code);
        return memberMapper.update(null,
                new LambdaUpdateWrapper<TMember>()
                        .set(TMember::getMobile, mobile)
                        .eq(TMember::getId, id))
                == 1;

    }

    /**
     * 校验注册验证码
     *
     * @param mobile
     * @param code
     */
    @Override
    public void authPhoneCode(String mobile, String code) {
        //查询验证码
        TVerifyCode tVerifyCode = verifyCodeMapper.selectOne(new LambdaQueryWrapper<TVerifyCode>()
                .eq(TVerifyCode::getMobile, mobile));
        if (tVerifyCode == null)
            throw new ResponseException(ExpCode.LOGIN_MOBILE_ERR.getCode(), ExpCode.LOGIN_MOBILE_ERR.getMsg());
        String vCode = tVerifyCode.getCode();
        LocalDateTime expireTime = tVerifyCode.getExpireTime();
        //校验 验证码
        if (!code.equals(vCode))
            throw new ResponseException(ExpCode.LOGIN_VCODE_ERR.getCode(), ExpCode.LOGIN_VCODE_ERR.getMsg());
        else if (LocalDateTime.now().isAfter(expireTime.plusSeconds(TimeUnit.MILLISECONDS.toSeconds(18000))))
            throw new ResponseException(ExpCode.LOGIN_VCODE_EXPIRE.getCode(), ExpCode.LOGIN_VCODE_EXPIRE.getMsg());


    }

    @Override
    public boolean authFace(String id, String url) {
        Check.state(StringUtils.isNotBlank(url), ExpCode.PARAMS_ILLEGAL);
        url = url.replace(ossConfig.getHostname() + "/", "");
        if (StringUtils.isBlank(url))
            return false;

        return memberMapper.update(null,
                new LambdaUpdateWrapper<TMember>()
                        .set(TMember::getFaceUrl, url)
                        .set(TMember::getFaceStatus, AuthFaceEnum.PROCESSING.getCode())
                        .eq(TMember::getId, id)) == 1;

    }

    @Override
    public PageResult<MemberDTO> usersCheckedList(int page, int size, String name, Integer faceStatus, String autoId) {
        LambdaQueryWrapperX<TMember> wrapper = new LambdaQueryWrapperX<TMember>()
                .orderByDesc(TMember::getLastVisitTime);
        if (name != null && name != null) {
            wrapper.likeIfPresent(TMember::getName, name);
        }
        if (faceStatus != null && faceStatus != null) {
            wrapper.eqIfPresent(TMember::getFaceStatus, faceStatus);
        }
        if (autoId != null && autoId != null) {
            wrapper.eqIfPresent(TMember::getAutoId, autoId);
        }

        Page<TMember> memberPage = memberMapper.selectPage(
                new Page<>(page, size),
                wrapper
        );

        PageResult<MemberDTO> result = new PageResult<MemberDTO>()
                .setCurrent(memberPage.getCurrent())
                .setPages(memberPage.getPages())
                .setSize(memberPage.getSize())
                .setTotal(memberPage.getTotal());

        for (TMember record : memberPage.getRecords()) {
            result.getRecords().add(
                    new MemberDTO()
                            .setAutoId(record.getAutoId())
                            .setName(record.getName())
                            .setNickName(record.getNickName())
                            .setMobile(record.getMobile())
                            .setAddTime(record.getAddTime())
                            .setLastVisitTime(record.getLastVisitTime())
                            .setFaceStatus(record.getFaceStatus())
                            .setFaceUrl(StringUtils.isBlank(record.getFaceUrl()) ? null : ossConfig.getHostname() + "/" + record.getFaceUrl())
                            .setRemarks(record.getRemarks())
            );
        }
        return result;
    }

    @Override
    public boolean checkedFaceStatus(String autoId, Integer faceStatus) {
        return memberMapper.update(null,
                new LambdaUpdateWrapper<TMember>()
                        .set(TMember::getFaceStatus, faceStatus)
                        .eq(TMember::getAutoId, autoId)) == 1;

    }

    @Override
    public PageResult<FollowOrderDTO> getMyAccessHistoryOrderList(String id, int pageNo, int pageSize) {
        String key = CacheKey.USER.userHistory + id;
        Long count = redis.zCard(key);
        if (count == 0)
            return new PageResult<>();

        int start = (pageNo - 1) * pageSize;
        Set<Object> values = redis.zRange(key, start, start + pageSize - 1);
        if (CollectionUtils.isEmpty(values))
            return new PageResult<>();

        String ids = values.stream().map(String::valueOf).collect(Collectors.joining(","));
        List<FollowOrderDTO> res = collectOrderMapper.selectAccessHistoryOrderListByIds(ids);
        ImmutableMap<Long, TProductCategory> cates = Maps.uniqueIndex(categoryMapper.selectAll(), TProductCategory::getId);
        ImmutableMap<String, FollowOrderDTO> map = Maps.uniqueIndex(res, FollowOrderDTO::getPublishOrderId);

        List<FollowOrderDTO> result = Arrays.stream(ids.split(","))
                .map(map::get)
                .filter(ObjectUtils::allNotNull)
                .map(item -> {
                    TProductCategory category = cates.get(Long.parseLong(item.getCategory()));
                    item.setCategory(category == null ? null : category.getCaption());
                    item.setImgUrl(StringUtils.isBlank(item.getImgUrl()) ? item.getImgUrl() : ossConfig.getHostname() + "/" + item.getImgUrl());
                    return item;
                }).collect(Collectors.toList());

        return new PageResult<FollowOrderDTO>()
                .setCurrent(pageNo)
                .setSize(pageSize)
                .setPages((count + pageSize - 1) / pageSize)
                .setTotal(count)
                .setRecords(result);
    }

    @Override
    public PageResult<ConsumeOrderCommentDTO> getMyCommentOrderList(String id, int pageNo, int pageSize, String type) {
        Page<C2cOrder> orderPages = orderMapper.selectPage(new Page<>(pageNo, pageSize),
                new LambdaQueryWrapper<C2cOrder>()
                        .select(C2cOrder::getPublishOrderId, C2cOrder::getId, C2cOrder::getPayTime, C2cOrder::getPayPrice)
                        .eq(C2cOrder::getMId, id)
                        .eq(C2cOrder::getOrderStatus, OrderStatusEnum.FINISH.getStatus())
                        .eq(C2cOrder::getCommentStatus, type));
        if (CollectionUtils.isEmpty(orderPages.getRecords()))
            return new PageResult<>();

        List<String> pIds = orderPages.getRecords().stream().map(C2cOrder::getPublishOrderId).collect(Collectors.toList());
        List<TPublishOrder> publishOrders = publishOrderMapper.selectList(new LambdaQueryWrapper<TPublishOrder>()
                .select(TPublishOrder::getOtherDesc, TPublishOrder::getId, TPublishOrder::getMId, TPublishOrder::getCategoryId, TPublishOrder::getCityName)
                .in(TPublishOrder::getId, pIds));

        List<Long> mIds = publishOrders.stream().map(TPublishOrder::getMId).collect(Collectors.toList());
        List<TMember> members = memberMapper.selectList(new LambdaQueryWrapper<TMember>()
                .select(TMember::getId, TMember::getNickName, TMember::getImgUrl, TMember::getArea)
                .in(TMember::getId, mIds));

        ImmutableMap<Long, TProductCategory> catesMap = Maps.uniqueIndex(categoryMapper.selectAll(), TProductCategory::getId);
        ImmutableMap<Long, TMember> memberMap = Maps.uniqueIndex(members, TMember::getId);
        ImmutableMap<String, TPublishOrder> publishMap = Maps.uniqueIndex(publishOrders, TPublishOrder::getId);

        return new PageResult<ConsumeOrderCommentDTO>()
                .setTotal(orderPages.getTotal())
                .setCurrent(orderPages.getCurrent())
                .setSize(orderPages.getSize())
                .setPages(orderPages.getPages())
                .setRecords(orderPages
                        .getRecords()
                        .stream()
                        .map(m ->
                                {
                                    ConsumeOrderCommentDTO dto = new ConsumeOrderCommentDTO();
                                    MemberShowInfo memberInfo = new MemberShowInfo();
                                    String publishOrderId = m.getPublishOrderId();
                                    TPublishOrder publishOrder = publishMap.get(publishOrderId);
                                    TMember member = memberMap.get(publishOrder == null ? -1 : publishOrder.getMId());
                                    TProductCategory cate = catesMap.get(publishOrder == null ? -1 : publishOrder.getCategoryId());
                                    if (member != null)
                                        memberInfo.setMId(member.getId() + "")
                                                .setImgUrl(StringUtils.isBlank(member.getImgUrl()) ? "" : ossConfig.getHostname() + "/" + member.getImgUrl())
                                                .setNickName(member.getNickName())
                                                .setArea(publishOrder == null ? parseArea(member.getArea()) : StringUtils.isBlank(publishOrder.getCityName()) ? parseArea(member.getArea()) : publishOrder.getCityName());

                                    return dto.setMember(memberInfo)
                                            .setCategory(cate == null ? "" : cate.getCaption())
                                            .setContent(publishOrder == null ? "" : publishOrder.getOtherDesc())
                                            .setDate(DateUtils.getLocalDateTimeStr(m.getPayTime(), DateUtils.YYYY_MM_DD))
                                            .setOrderId(m.getId())
                                            .setTips("0".equals(type) ? "未评价" : "已评价")
                                            .setPrice(m.getPayPrice().toString());
                                }
                        )
                        .sorted(Comparator.comparing(ConsumeOrderCommentDTO::getDate).reversed())
                        .collect(Collectors.toList()));

    }

    @Override
    public PageResult<RecommendMemberDTO> getRecommendMemberList(int pageNo, int pageSize, String auto, String gender, Integer age) {
        //auto = "0".equalsIgnoreCase(auto) ? "t" : null;
        auto = StringUtils.isBlank(auto) ? null : auto;
        gender = StringUtils.isBlank(gender) ? null : gender;
        Page<RecommendMemberDTO> page = memberRecommendMapper.selectRecommendList(new Page<>(pageNo, pageSize), auto, gender, age);
        PageResult<RecommendMemberDTO> res = new PageResult<RecommendMemberDTO>()
                .setPages(page.getPages())
                .setCurrent(page.getCurrent())
                .setSize(page.getSize())
                .setTotal(page.getTotal());
        return Optional.ofNullable(page.getRecords())
                .filter(org.apache.commons.collections4.CollectionUtils::isNotEmpty)
                .map(m -> {
                    ImmutableMap<String, RecommendMemberDTO> recommendMemberMap = Maps.uniqueIndex(m, RecommendMemberDTO::getMId);
                    ImmutableMap<Long, TProductCategory> cates = Maps.uniqueIndex(categoryMapper.selectAll(), TProductCategory::getId);
                    List<String> mIds = m.stream().map(RecommendMemberDTO::getMId).collect(Collectors.toList());
                    publishOrderMapper
                            .selectList(new LambdaQueryWrapper<TPublishOrder>()
                                    .select(TPublishOrder::getId, TPublishOrder::getCategoryId, TPublishOrder::getPrice, TPublishOrder::getUnit,
                                            TPublishOrder::getMId, TPublishOrder::getOtherDesc, TPublishOrder::getCityName)
                                    .in(TPublishOrder::getMId, mIds)
                                    .eq(TPublishOrder::getStatus, CommonStatus.NORMAL.getType()))
                            .stream().filter(f -> StringUtils.isNotBlank(f.getId()))
                            .forEach(f -> {
                                TProductCategory cate = Optional.ofNullable(cates.get(f.getCategoryId())).orElse(new TProductCategory());
                                RecommendMemberDTO dto = recommendMemberMap.get(String.valueOf(f.getMId()));
                                if (dto.getCategory().equals(cate.getCaption())) {
                                    dto.setPublishOrderId(f.getId())
                                            .setPrice(f.getPrice().intValue() + "")
                                            .setUnit(f.getUnit() == 0 ? "/h" : "天")
                                            .setOtherDesc(f.getOtherDesc())
                                            .setArea(StringUtils.isBlank(f.getCityName()) ? parseArea(dto.getArea()) : f.getCityName())
                                            .setOnline(DateUtils.computeOnlineTime(dto.getLastVisitTime()));
                                }

                            });

                    return res.setRecords(m.stream()
                            .map(item -> item.setImgUrl(StringUtils.isBlank(item.getImgUrl()) ? "" : ossConfig.getHostname() + "/" + item.getImgUrl())).collect(Collectors.toList()));
                }).orElse(res);
    }


    @Override
    public Function<MsgQueryParams, PageResult<SystemMsgResult>> getSystemMsgList() {
        return msgQueryParams -> {
            Page<TSystemPushMsg> page = systemPushMsgMapper
                    .selectPage(
                            new Page<>(msgQueryParams.getPageNo(), msgQueryParams.getPageSize()),
                            new LambdaQueryWrapper<TSystemPushMsg>()
                                    .select(TSystemPushMsg::getContent, TSystemPushMsg::getId, TSystemPushMsg::getCreateTime, TSystemPushMsg::getType)
                                    .eq(TSystemPushMsg::getType, SystemMsgEnum.SYSTEM.getType())
                                    .orderByDesc(TSystemPushMsg::getCreateTime)

                    );
            return new PageResult<SystemMsgResult>()
                    .setRecords(page
                            .getRecords()
                            .stream()
                            .map(m ->
                                    new SystemMsgResult()
                                            .setContent(m.getContent())
                                            .setDate(DateUtils.getLocalDateTimeStr(m.getCreateTime()))
                                            .setNickName("系统消息")
                                            .setType(m.getType() + "")
                                            .setId(m.getId())

                            )
                            .collect(Collectors.toList()))
                    .setTotal(page.getTotal())
                    .setCurrent(page.getCurrent())
                    .setSize(page.getSize())
                    .setPages(page.getPages());
        };
    }

    @Override
    public Function<MsgQueryParams, PageResult<SystemMsgResult>> getDynamicMsgList() {
        return msgQueryParams -> {
            //查询推送过的历史消息
            Page<TSystemPushMsg> page = systemPushMsgMapper
                    .selectPage(
                            new Page<>(msgQueryParams.getPageNo(), msgQueryParams.getPageSize()),
                            new LambdaQueryWrapper<TSystemPushMsg>()
                                    .select(TSystemPushMsg::getContent, TSystemPushMsg::getId, TSystemPushMsg::getCreateTime, TSystemPushMsg::getType)
                                    .eq(TSystemPushMsg::getReceiverId, msgQueryParams.getMId())
                                    .eq(TSystemPushMsg::getType, SystemMsgEnum.DYNAMIC.getType())
                                    .orderByDesc(TSystemPushMsg::getCreateTime)

                    );
            //解析消息参数
            List<InteractiveMsgParams> contents = page.getRecords().stream().map(m -> JSONObject.parseObject(m.getContent(), InteractiveMsgParams.class)).collect(Collectors.toList());
            if (org.apache.commons.collections4.CollectionUtils.isEmpty(contents))
                return new PageResult<>();

            //查询动态互动 用户参数
            List<TMember> members = memberMapper.selectList(new LambdaQueryWrapper<TMember>()
                    .select(TMember::getId, TMember::getNickName, TMember::getImgUrl)
                    .in(TMember::getId, contents.stream()
                            .map(InteractiveMsgParams::getMId).collect(Collectors.toList())));

            //type >0 评论id
            List<String> commentIds = contents
                    .stream()
                    .filter(f -> f.getType() > 0)
                    .map(InteractiveMsgParams::getId)
                    .collect(Collectors.toList());
            //type <0 动态id
            List<String> dynamicIds = contents
                    .stream()
                    .filter(f -> f.getType() < 0)
                    .map(InteractiveMsgParams::getId)
                    .collect(Collectors.toList());

            List<TDynamicComment> dynamicComments = null;
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(commentIds))
                dynamicComments = dynamicCommentMapper.selectList(new LambdaQueryWrapper<TDynamicComment>()
                        .select(TDynamicComment::getDynamicId, TDynamicComment::getMessage, TDynamicComment::getId)
                        .in(TDynamicComment::getId, commentIds));

            if (dynamicComments != null)
                dynamicIds.addAll(dynamicComments.stream().map(m -> m.getDynamicId() + "").collect(Collectors.toList()));

            List<TMemberDynamic> dynamicList = dynamicMapper.selectList(new LambdaQueryWrapper<TMemberDynamic>()
                    .select(TMemberDynamic::getId, TMemberDynamic::getTitle)
                    .in(TMemberDynamic::getId, dynamicIds));

            ImmutableMap<Long, TDynamicComment> commentMaps =
                    Maps.uniqueIndex(dynamicComments == null ? Lists.newArrayList() : dynamicComments, TDynamicComment::getId);
            ImmutableMap<Long, TMemberDynamic> dynamicMaps = Maps.uniqueIndex(dynamicList == null ? Lists.newArrayList() : dynamicList, TMemberDynamic::getId);
            ImmutableMap<Long, TMember> memberMaps = Maps.uniqueIndex(members == null ? Lists.newArrayList() : members, TMember::getId);

            return new PageResult<SystemMsgResult>()
                    .setRecords(page
                            .getRecords()
                            .stream()
                            .map(m -> {
                                        InteractiveMsgParams params = JSONObject.parseObject(m.getContent(),
                                                InteractiveMsgParams.class);
                                        Long id = Long.parseLong(params.getId());
                                        TDynamicComment comment = commentMaps.get(id);
                                        TMemberDynamic dynamic = params.getType() > 0 ?
                                                dynamicMaps.get(Optional.ofNullable(comment).orElse(new TDynamicComment()).getDynamicId()) :
                                                dynamicMaps.get(id);
                                        TMember member = memberMaps.get(Long.parseLong(params.getMId()));
                                        return new SystemMsgResult()
                                                .setId(m.getId())
                                                .setContent(comment == null ? "赞了我的动态" : "回复：" + comment.getMessage())
                                                .setSubject(dynamic == null ? "" : dynamic.getTitle())
                                                .setSubjectId(dynamic == null ? "" : dynamic.getId().toString())
                                                .setNickName(member == null ? "" : member.getNickName())
                                                .setMId(member == null ? "" : String.valueOf(member.getId()))
                                                .setImgUrl(member == null ? "" : ossConfig.getHostname() + "/" + member.getImgUrl())
                                                .setDate(DateUtils.getLocalDateTimeStr(m.getCreateTime()))
                                                .setType(m.getType() + "");
                                    }
                            )
                            .collect(Collectors.toList()))
                    .setTotal(page.getTotal())
                    .setCurrent(page.getCurrent())
                    .setSize(page.getSize())
                    .setPages(page.getPages());
        };
    }

    @Override
    public Function<MsgQueryParams, PageResult<SystemMsgResult>> getOrderCommentMsgList() {
        return msgQueryParams -> {
            Page<TSystemPushMsg> page = systemPushMsgMapper
                    .selectPage(
                            new Page<>(msgQueryParams.getPageNo(), msgQueryParams.getPageSize()),
                            new LambdaQueryWrapper<TSystemPushMsg>()
                                    .select(TSystemPushMsg::getContent, TSystemPushMsg::getId, TSystemPushMsg::getCreateTime, TSystemPushMsg::getType)
                                    .eq(TSystemPushMsg::getReceiverId, msgQueryParams.getMId())
                                    .eq(TSystemPushMsg::getType, SystemMsgEnum.COMMENT.getType())
                                    .orderByDesc(TSystemPushMsg::getCreateTime)

                    );

            List<InteractiveMsgParams> contents = page.getRecords().stream().map(m -> JSONObject.parseObject(m.getContent(), InteractiveMsgParams.class)).collect(Collectors.toList());

            List<Object> commentIds =
                    contents
                            .stream()
                            .map(InteractiveMsgParams::getId)
                            .collect(Collectors.toList());
            if (org.apache.commons.collections4.CollectionUtils.isEmpty(commentIds))
                return new PageResult<>();

            List<TOrderComment> orderComments = orderCommentMapper.selectList(new LambdaQueryWrapper<TOrderComment>()
                    .select(TOrderComment::getId, TOrderComment::getContent, TOrderComment::getOrderId, TOrderComment::getAddTime)
                    .in(TOrderComment::getId, commentIds));

            List<Long> orderIds = orderComments.stream().map(TOrderComment::getOrderId).collect(Collectors.toList());

            List<C2cOrder> c2cOrders = orderMapper.selectList(new LambdaQueryWrapper<C2cOrder>()
                    .select(C2cOrder::getId, C2cOrder::getPublishOrderId)
                    .in(C2cOrder::getId, orderIds));

            List<TPublishOrder> publishOrders = publishOrderMapper.selectList(new LambdaQueryWrapper<TPublishOrder>()
                    .select(TPublishOrder::getOtherDesc, TPublishOrder::getId)
                    .in(TPublishOrder::getId, c2cOrders.stream().map(C2cOrder::getPublishOrderId).collect(Collectors.toList())));

            List<TMember> members = memberMapper.selectList(new LambdaQueryWrapper<TMember>()
                    .select(TMember::getId, TMember::getNickName, TMember::getImgUrl)
                    .in(TMember::getId, contents.stream()
                            .map(InteractiveMsgParams::getMId).collect(Collectors.toList())));

            ImmutableMap<Long, TMember> memberMaps = Maps.uniqueIndex(members == null ? Lists.newArrayList() : members, TMember::getId);
            ImmutableMap<Long, TOrderComment> commentMaps = Maps.uniqueIndex(orderComments, TOrderComment::getId);
            ImmutableMap<String, C2cOrder> orderMaps = Maps.uniqueIndex(c2cOrders, C2cOrder::getId);
            ImmutableMap<String, TPublishOrder> publishOrderMaps = Maps.uniqueIndex(publishOrders == null ? Lists.newArrayList() : publishOrders, TPublishOrder::getId);
            return new PageResult<SystemMsgResult>()
                    .setRecords(page
                            .getRecords()
                            .stream()
                            .map(m -> {
                                        InteractiveMsgParams params = JSONObject.parseObject(m.getContent(),
                                                InteractiveMsgParams.class);
                                        Long id = Long.parseLong(params.getId());
                                        TMember member = memberMaps.get(Long.parseLong(params.getMId()));
                                        TOrderComment comment = commentMaps.get(id);
                                        C2cOrder order = comment == null ? null : orderMaps.get(comment.getOrderId().toString());
                                        TPublishOrder publishOrder = order == null ? null : publishOrderMaps.get(order.getPublishOrderId());
                                        return new SystemMsgResult()
                                                .setId(m.getId())
                                                .setContent(comment == null ? "" : "评价：" + comment.getContent())
                                                .setSubject(publishOrder == null ? "" : publishOrder.getOtherDesc())
                                                .setSubjectId(publishOrder == null ? "" : publishOrder.getId())
                                                .setNickName(member == null ? "" : member.getNickName())
                                                .setMId(member == null ? "" : String.valueOf(member.getId()))
                                                .setImgUrl(member == null ? "" : ossConfig.getHostname() + "/" + member.getImgUrl())
                                                .setDate(comment == null ? DateUtils.getLocalDateTimeStr(m.getCreateTime()) : DateUtils.parseDateToStr(DateUtils.MM_DD_HH_MM, comment.getAddTime()))
                                                .setType(m.getType() + "");
                                    }
                            )
                            .collect(Collectors.toList()))
                    .setTotal(page.getTotal())
                    .setCurrent(page.getCurrent())
                    .setSize(page.getSize())
                    .setPages(page.getPages());


        };
    }

    @Override
    public PageResult<MemberShowInfo> getVisitList(String id, int pageNo, int pageSize) {
        Page<MemberShowInfo> ret = memberVisitMapper.selectVisitList(new Page(pageNo, pageSize), id);
        return new PageResult<MemberShowInfo>()
                .setTotal(ret.getTotal())
                .setSize(ret.getSize())
                .setCurrent(ret.getCurrent())
                .setPages(ret.getPages())
                .setRecords(
                        ret
                                .getRecords()
                                .stream()
                                .filter(Objects::nonNull)
                                .map(m -> m.setImgUrl(
                                        StringUtils.isBlank(m.getImgUrl()) ? "" : ossConfig.getHostname() + "/" + m.getImgUrl())
                                        .setArea(parseArea(m.getArea()))

                                )
                                .collect(Collectors.toList())

                );
    }

    @Override
    public PageResult<MemberDTO> usersIdentityList(int page, int size, Integer status, String autoId, String id) {
        Page<TMember> res = memberMapper.selectPage(
                new Page<>(page, size),
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getAutoId, TMember::getId, TMember::getName, TMember::getNickName, TMember::getIdUrl, TMember::getIdStatus, TMember::getIdentity)
                        .eq(TMember::getIdStatus, status)
                        .eq(StringUtils.isNotBlank(autoId), TMember::getAutoId, autoId)
                        .eq(StringUtils.isNotBlank(id), TMember::getId, id)
                        .orderByDesc(TMember::getLastVisitTime));
        List<MemberDTO> ret = res
                .getRecords()
                .stream()
                .map(m ->
                        {
                            List<String> urls = strToList(",", m.getIdUrl())
                                    .stream()
                                    .map(url -> StringUtils.isBlank(url) ? "" : ossConfig.getHostname() + "/" + url)
                                    .collect(Collectors.toList());
                            MemberDTO dto = new MemberDTO();
                            return dto.setAutoId(m.getAutoId())
                                    .setId(m.getId())
                                    .setName(m.getName())
                                    .setIdentity(m.getIdentity())
                                    .setNickName(m.getNickName())
                                    .setIdStatus(m.getIdStatus())
                                    .setIdUrls(urls);

                        }
                ).collect(Collectors.toList());
        return new PageResult<MemberDTO>()
                .setRecords(ret)
                .setPages(res.getPages())
                .setCurrent(res.getCurrent())
                .setSize(res.getSize())
                .setTotal(res.getTotal());

    }

    @Override
    public boolean identityStatus(String autoId, Integer status) {
        return memberMapper.update(null,
                new LambdaUpdateWrapper<TMember>()
                        .set(TMember::getIdStatus, status)
                        .eq(TMember::getAutoId, autoId)) == 1;
    }

    @Override
    public void pullSystemSession(String id) {
        tencentComponent.batchPushMsg(1, id, Arrays.asList(imConfig.getCommentAcc()), ImMsgType.text.getCode(), "新的交易评价在这里");
        tencentComponent.batchPushMsg(1, id, Arrays.asList(imConfig.getDynamicAcc()), ImMsgType.text.getCode(), "动态圈子讨论区");
        tencentComponent.batchPushMsg(1, id, Arrays.asList(imConfig.getAdminAcc()), ImMsgType.text.getCode(), "关于行为规范");
    }

    @Override
    public MemberSpreadDataDTO getMemberSpreadData(String id) {
        List<TSpreadSetting> settingList = spreadSettingMapper.selectList(null);
        TMember member = memberMapper.selectOne(new QueryWrapper<>(new TMember().setId(Parse.toLong(id))));
        Check.notNull(member, ExpCode.LOGIN_TOKEN_EXPIRED);
        Integer serviceCount = memberMapper.selectCount(new QueryWrapper<>(new TMember().setParentId(member.getAutoId()).setIdStatus(CommonStatus.NORMAL.getType())));
        BigDecimal totalProfit = memberBalanceLogMapper.selectSumMoney(id, BalanceLogEnum.SPREAD_PROFIT.getType());
        BigDecimal scale = settingList.stream().filter(f -> f.getConditions() <= serviceCount).map(TSpreadSetting::getScale).max(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
        List<TSpreadProfitList> profitLists = spreadProfitListMapper.selectList(
                new LambdaQueryWrapper<TSpreadProfitList>()
                        .orderByDesc(TSpreadProfitList::getMoney)
        );
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(profitLists))
            profitLists = memberBalanceLogMapper.selectProfitList().stream().map(m -> m.setName(m.getName().substring(0, 1) + "**")).collect(Collectors.toList());

        return new MemberSpreadDataDTO()
                .setDescList(settingList)
                .setServiceCount(serviceCount)
                .setProfitMoney(totalProfit)
                .setScale(scale.toString())
                .setPersonCount(memberMapper.selectCount(null))
                .setProfitList(profitLists);


    }

    @Override
    public PageResult<MemberSpreadList> getMemberSpreadList(String id, int pageNo, int pageSize) {

        Page<MemberSpreadList> res = memberBalanceLogMapper.selectSpreadList(
                new Page<>(pageNo, pageSize),
                id
        );
        return new PageResult<MemberSpreadList>()
                .setTotal(res.getTotal())
                .setRecords(res.getRecords())
                .setSize(res.getSize())
                .setCurrent(res.getCurrent())
                .setPages(res.getPages());


    }

    @Transactional
    @Override
    public boolean identityCheckedNew(String mId, String name, int sex, String bir, String lifeUrl, String idCode, String urls) {
        TMember member = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getAutoId, TMember::getIdentity, TMember::getIdStatus, TMember::getId)
                        .eq(TMember::getId, mId)
        );
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        Check.state(member.getIdStatus() < AuthFaceEnum.PROCESSING.getCode(), ExpCode.AUTH_EXISTS);

//        List<TMemberAlbum> albums = Arrays.stream(lifeUrl.split(","))
//                .map(url -> new TMemberAlbum()
//                        .setUrl(url)
//                        .setAddTime(LocalDateTime.now())
//                        .setOrderNum(1)
//                        .setType(2)
//                        .setStatus(1)
//                        .setMId(member.getId())
//                )
//                .collect(Collectors.toList());
//        Integer albumRow = memberAlbumMapper.insertBatchSomeColumn(albums);

        int row = memberMapper.update(null,
                new LambdaUpdateWrapper<TMember>()
                        .set(TMember::getName, name)
                        .set(TMember::getGender, sex)
                        .set(TMember::getBirthday, bir)
                        .set(TMember::getAge, LocalDate.now().getYear() - Parse.toInt(idCode.substring(6, 10), 2000))
                        .set(TMember::getIdentity, idCode)
                        .set(TMember::getIdUrl, urls)
                        .set(TMember::getIdStatus, AuthFaceEnum.PROCESSING.getCode())
                        .eq(TMember::getId, member.getId()));
        Check.state(row == 1, ExpCode.DB_UPDATE_ERR);
        return true;
    }

    @Override
    public String getHomeBackground(Long id) {
        List<TMemberAlbum> bg = memberAlbumMapper.selectList(new QueryWrapper<>(new TMemberAlbum().setMId(id).setType(3)));

        return CollectionUtils.isEmpty(bg) || StringUtils.isBlank(bg.get(0).getUrl()) ? ""
                : ossConfig.getHostname() + "/" + bg.get(0).getUrl();
    }

    @Override
    public void addBackGround(String id, String url) {
        // boolean vip = isVip(id);
        // if (vip) {
        memberAlbumMapper.delete(new QueryWrapper<>(new TMemberAlbum().setMId(Parse.toLong(id)).setType(3)));
        memberAlbumMapper.insert(new TMemberAlbum()
                .setMId(Parse.toLong(id))
                .setType(3)
                .setStatus(1)
                .setUrl(url)
        );
        // }

    }

    @Override
    public ActionDTO actionCheck(String id) {
        LocalDateTime time = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        Integer dispatchCount = dispatchOrderMapper
                .selectCount(
                        new LambdaQueryWrapper<TDispatchOrder>()
                                .eq(TDispatchOrder::getMId, id)
                                .eq(TDispatchOrder::getBeforeStatus, PayStatusEnum.FINISH)
                                .ge(TDispatchOrder::getAddTime, time)
                );
        Integer publishCount = publishOrderMapper.selectCount(
                new LambdaQueryWrapper<TPublishOrder>()
                        .eq(TPublishOrder::getMId, id)
                        .ge(TPublishOrder::getStatus, OrderStatusEnum.AWAIT)
                        .ge(TPublishOrder::getAddTime, time)
        );
        return new ActionDTO().setDispatchOrder(dispatchCount == 0).setPublishOrder(publishCount == 0);
    }


    @Override
    public Function<MsgQueryParams, PageResult<SystemMsgResult>> getPersonalMsgList() {
        return msgQueryParams -> {
            Page<TSystemPushMsg> page = systemPushMsgMapper
                    .selectPage(
                            new Page<>(msgQueryParams.getPageNo(), msgQueryParams.getPageSize()),
                            new LambdaQueryWrapper<TSystemPushMsg>()
                                    .select(TSystemPushMsg::getContent, TSystemPushMsg::getId, TSystemPushMsg::getCreateTime, TSystemPushMsg::getType)
                                    .eq(TSystemPushMsg::getReceiverId, msgQueryParams.getMId())
                                    .eq(TSystemPushMsg::getType, SystemMsgEnum.PERSONAL.getType())
                                    .orderByDesc(TSystemPushMsg::getCreateTime)

                    );
            return new PageResult<SystemMsgResult>()
                    .setRecords(page
                            .getRecords()
                            .stream()
                            .map(m ->
                                    new SystemMsgResult()
                                            .setContent(m.getContent())
                                            .setDate(DateUtils.getLocalDateTimeStr(m.getCreateTime()))
                                            .setNickName("个人消息")
                                            .setType(m.getType() + "")
                                            .setId(m.getId())

                            )
                            .collect(Collectors.toList()))
                    .setTotal(page.getTotal())
                    .setCurrent(page.getCurrent())
                    .setSize(page.getSize())
                    .setPages(page.getPages());
        };
    }
}
